﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace tiDE.SourceInsight
{
    public class z80SourceInsight : ISourceInsightProvider
    {
        public string[] SupportedFileTypes
        {
            get { return new string[] 
                {
                    ".z80",
                    ".asm",
                }; }
        }

        public List<SourceLocation> GetSourceLocations(string Source, string SourceFile)
        {
            List<SourceLocation> sourceLocations = new List<SourceLocation>();
            int lineNumber = 0;
            string[] lines = Source.Replace("\r", "").Split('\n');
            foreach (string line in lines)
            {
                string thisLine = line.Clone() as string;
                int oldLength = thisLine.Length;
                thisLine = thisLine.TrimStart();
                int startIndex = oldLength - thisLine.Length;
                thisLine = thisLine.Trim();
                thisLine = Assembler.StripComments(thisLine).Trim();
                if (thisLine.EndsWith(":"))
                {
                    thisLine = thisLine.Replace(":", "");
                    sourceLocations.Add(new SourceLocation(lineNumber, startIndex, thisLine.Length, thisLine));
                }
                lineNumber++;
            }
            return sourceLocations;
        }

        public string BitmapToSource(Bitmap Bitmap, int numLevels)
        {
            string source = "; Image: " + Bitmap.Width + "x" + Bitmap.Height + System.Environment.NewLine + "Image0:";

            if (numLevels == 3)
                numLevels++;

            int imageSizePerBuffer = Bitmap.Width / 8 + (Bitmap.Width % 8 == 0 ? 0 : 1);
            imageSizePerBuffer *= Bitmap.Height;

            int numBuffers = (int)Math.Ceiling(Math.Log(numLevels, 2));

            byte threshold = (byte)(256 / (numLevels - 1));
            if (threshold == 0)
                threshold = 255;

            byte[][] buffers = new byte[numBuffers][];
            for (int i = 0; i < buffers.Length; i++)
                buffers[i] = new byte[imageSizePerBuffer];

            byte bitMask = 0x01;
            int byteIndex = 0;

            for (int y = 0; y < Bitmap.Height; y++)
            {
                for (int x = 0; x < Bitmap.Width; x++)
                {
                    Color color = Bitmap.GetPixel(x, y);
                    byte avgColor = color.R;
                    int currentThreshold = 0, clippedColor = 0;
                    // Clipped color represents the index in gray
                    while (avgColor > currentThreshold)
                    {
                        currentThreshold += threshold;
                        clippedColor++;
                    }
                    // Use the bits of clippedColor to deterimine which buffers to put it into
                    byte mask = 0x01;
                    for (int i = 0; i < numBuffers; i++)
                    {
                        if ((clippedColor & mask) != 0)
                        {
                            buffers[i][byteIndex] |= bitMask;
                        }
                        mask = (byte)(mask << 1);
                    }
                    bitMask = (byte)(bitMask << 1);
                    if (bitMask == 0)
                    {
                        bitMask = 0x01;
                        byteIndex++;
                    }
                }
                if (bitMask != 1)
                    byteIndex++;
            }

            foreach (byte[] buffer in buffers)
            {
                source += System.Environment.NewLine + ".db ";
                foreach (byte b in buffer)
                {
                    source += "$" + AddPadding(((byte)~b).ToString("x")).ToUpper() + ", ";
                }
                source = source.Remove(source.Length - 2);
            }

            return source;
        }

        string AddPadding(string hex)
        {
            if (hex.Length != 2)
                hex = "0" + hex;
            return hex;
        }

        public Bitmap SourceToBitmap(string source, int numLevels, int Width, int Height)
        {
            return new Bitmap(Width, Height);
        }

        #region z80 Specific Insights

        public static List<string> GetLocalLabels(string Source)
        {
            List<string> labels = new List<string>();
            string[] lines = Source.Replace("\r", "").Split('\n');
            foreach (string line in lines)
            {
                string thisLine = line.Clone() as string;
                thisLine = thisLine.Trim();
                thisLine = Assembler.StripComments(thisLine).Trim();
                if (thisLine.EndsWith(":"))
                {
                    thisLine = thisLine.Replace(":", "");
                    labels.Add(thisLine);
                }
            }
            return labels;
        }

        #endregion
    }
}
